home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_073 / dio / dio.c next >
C/C++ Source or Header  |  1992-05-06  |  10KB  |  388 lines

  1.  
  2. /*
  3.  *  DIO.C
  4.  *  MUST BE COMPILED USING 32 BIT INTS
  5.  *  (C)Copyright 1987 by Matthew Dillon.
  6.  *  Freely distributable.  Donations Welcome, I guess.
  7.  *
  8.  *    Matthew Dillon
  9.  *    891 Regal Rd.
  10.  *    Berkeley, Ca. 94708
  11.  *
  12.  * 
  13.  *  EXEC device driver IO support routines... makes everything easy.
  14.  *
  15.  *  dfd = dio_open(name, unit, flags, req/NULL)
  16.  *
  17.  *    open an IO device.  Note: in some cases you might have to provide
  18.  *    a request structure with some fields initialized (example, the
  19.  *    console device requires certain fields to be initialized).  For
  20.  *    instance, if openning the SERIAL.DEVICE, you would want to give
  21.  *    an IOExtSer structure which is completely blank execept for the
  22.  *    io_SerFlags field.
  23.  *
  24.  *    The request structure's message and reply ports need not be
  25.  *    initialized.  The request structure is no longer needed after
  26.  *    the dio_open().
  27.  *
  28.  *    NULL = error, else descriptor (a pointer) returned.
  29.  *
  30.  *
  31.  *  dio_close(dfd)
  32.  *
  33.  *    close an IO device.  Any pending asyncronous requests are
  34.  *    AbortIO()'d and then Wait'ed on for completion.
  35.  *
  36.  *
  37.  *  dio_closegrp(dfd)
  38.  *
  39.  *    close EVERY DIO DESCRIPTOR ASSOCIATED WITH THE dio_open() call
  40.  *    that was the parent for this descriptor.  That is, you can get
  41.  *    a descriptor using dio_open(), dio_dup() it a couple of times,
  42.  *    then use dio_closegrp() on any ONE of the resulting descriptors
  43.  *    to close ALL of them.
  44.  *
  45.  *
  46.  *  dio_cact(dfd,bool)
  47.  *
  48.  *    If an error occurs (io_Error field), the io_Actual field is usually
  49.  *    not modified by the device driver, and thus contains garbage.  To
  50.  *    provide a cleaner interface, you can have DIO_CTL() and DIO_CTL_TO()
  51.  *    calls automatically pre-clear this field so if an io_Error does
  52.  *    occur, the field is a definate 0 instead of garbage.
  53.  *
  54.  *    In most cases you will want to do this.  An exception is the
  55.  *    TIMER.DEVICE, which uses the io_Actual field for part of the
  56.  *    timeout structure.
  57.  *
  58.  *    This flags the particular dio descriptor to do the pre-clear, and
  59.  *    any new descriptors obtained by DIO_DUP()ing this one will also
  60.  *    have the pre-clear flag set.
  61.  *
  62.  *
  63.  *  dio_dup(dfd)
  64.  *
  65.  *    Returns a new channel descriptor referencing the same device.
  66.  *    The new descriptor has it's own signal and IO request structure.
  67.  *    For instance, if you openned the serial device, you might want
  68.  *    to dup the descriptor so you can use one channel to pend an
  69.  *    asyncronous read, and the other channel to write out to the device
  70.  *    and do other things without disturbing the asyncronous read.
  71.  *
  72.  *
  73.  *  sig = dio_signal(dfd)
  74.  *
  75.  *    get the signal number (0..31) used for a DIO descriptor.
  76.  *    This allows you to Wait() for asyncronous requests.  Note that
  77.  *    if your Wait() returns, you should double check using dio_isdone()
  78.  *
  79.  *
  80.  *  req = dio_ctl_to(dfd, command, buf, len, to)
  81.  *
  82.  *    Same as DIO_CTL() below, but (A) is always syncronous, and
  83.  *    (B) will attempt to AbortIO()+WaitIO() the request if the
  84.  *    timeout occurs before the IO completes.
  85.  *
  86.  *    the 'to' argument is in microseconds.
  87.  *
  88.  *
  89.  *  req = dio_ctl(dfd, command, buf, len)
  90.  *
  91.  *    DIO_CTL() is the basis for the entire library.    It works as follows:
  92.  *
  93.  *    (1) If the channel isn't clear (there is an asyncronous IO request
  94.  *        still pending), DIO_CTL() waits for it to complete
  95.  *
  96.  *    (2) If the command is 0, simply return a pointer to the io
  97.  *        request structure.
  98.  *
  99.  *    (3) If the DIO_CACT() flag is TRUE, the io_Actual field of the
  100.  *        request is cleared.
  101.  *
  102.  *    (4) Set the io_Data field to 'buf', and io_Length field to 'len'
  103.  *        If the command is positive, use DoIO().  If the command
  104.  *        negative, take it's absolute value and then do a SendIO().
  105.  *        (The command is placed in the io_Command field, of course).
  106.  *
  107.  *    (5) return the IO request structure
  108.  *
  109.  *
  110.  *  bool= dio_isdone(dfd)
  111.  *
  112.  *    return 1 if current channel is clear (done processing), else 0.
  113.  *    e.g. if you did, say, an asyncronous read, and dio_isdone() returns
  114.  *    true, you can now use the data buffer returned and look at the
  115.  *    io_Actual field.
  116.  *
  117.  *    You need not do a dio_wait() after dio_isdone() returns 1.
  118.  *
  119.  *
  120.  *  req = dio_wait(dfd)
  121.  *
  122.  *    Wait on the current channel for the request to complete and
  123.  *    then return the request structure. (nop if channel is clear)
  124.  *
  125.  *
  126.  *  req = dio_abort(dfd)
  127.  *
  128.  *    Abort the request on the current channel (nop if channel is
  129.  *    clear).  Sends an AbortIO() if the channel is active and then
  130.  *    WaitIO()'s the request.
  131.  *
  132.  *
  133.  *  MACROS: SEE DIO.H
  134.  *
  135.  */
  136.  
  137. #include <exec/types.h>
  138. #include <exec/io.h>
  139. #include <exec/memory.h>
  140. #include <exec/ports.h>
  141. #include <devices/timer.h>
  142. #include "xmisc.h"
  143.  
  144. #define MPC        (MEMF_CLEAR|MEMF_PUBLIC)
  145. #define CPORT        ior.ior.io_Message.mn_ReplyPort
  146. #define MAXREQSIZE  128     /* big enough to hold all Amiga iorequests */
  147.  
  148. typedef struct IORequest IOR;
  149. typedef struct IOStdReq  STD;
  150. typedef struct MsgPort     PORT;
  151.  
  152. typedef struct {
  153.     STD ior;
  154.     char filler[MAXREQSIZE-sizeof(STD)];
  155. } MAXIOR;
  156.  
  157. typedef struct {
  158.     struct _CHAN *list;
  159.     short refs;
  160. } DIO;
  161.  
  162. typedef struct _CHAN {
  163.     MAXIOR  ior;
  164.     DIO     *base;
  165.     XLIST   link;    /* doubly linked list */
  166.     STD     timer;
  167.     char    notclear;
  168.     char    cact;    /* automatic io_Actual field clear  */
  169. } CHAN;
  170.  
  171. extern CHAN *dio_ctl(), *dio_ctl_to(), *dio_wait(), *dio_abort();
  172. extern PORT *CreatePort();
  173. extern char *AllocMem();
  174.  
  175. CHAN *
  176. dio_open(name, unit, flags, req)
  177. char *name;
  178. MAXIOR *req;     /* not really this big  */
  179. {
  180.     register CHAN *chan;
  181.     register DIO *dio;
  182.     register PORT *port;
  183.     int ret;
  184.  
  185.     dio = (DIO *)AllocMem(sizeof(DIO), MPC);    if (!dio)   goto fail3;
  186.     chan= (CHAN *)AllocMem(sizeof(CHAN), MPC);    if (!chan)   goto fail2;
  187.     if (req)
  188.     chan->ior = *req;
  189.     chan->CPORT = CreatePort(NULL,0);        if (!chan->CPORT) goto fail1;
  190.     chan->ior.ior.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  191.     chan->base = dio;
  192.     dio->refs = 1;
  193.     if (OpenDevice(name, unit, &chan->ior, flags)) {
  194.     DeletePort(chan->CPORT);
  195. fail1:    FreeMem(chan, sizeof(CHAN));
  196. fail2:    FreeMem(dio, sizeof(DIO));
  197. fail3:    return(NULL);
  198.     }
  199.     llink(&dio->list, &chan->link);
  200.     chan->ior.ior.io_Flags = 0;
  201.     return(chan);
  202. }
  203.  
  204. void
  205. dio_cact(chan,n)
  206. CHAN *chan;
  207. {
  208.     if (chan)
  209.     chan->cact = n;
  210. }
  211.  
  212. void
  213. dio_close(chan)
  214. register CHAN *chan;
  215. {
  216.     if (chan) {
  217.     dio_abort(chan);
  218.     lunlink(&chan->link);
  219.     if (--chan->base->refs == 0) {
  220.         FreeMem(chan->base, sizeof(DIO));
  221.         CloseDevice(&chan->ior);
  222.     }
  223.     if (chan->timer.io_Message.mn_ReplyPort)
  224.         CloseDevice(&chan->timer);
  225.     DeletePort(chan->CPORT);
  226.     FreeMem(chan, sizeof(CHAN));
  227.     }
  228. }
  229.  
  230.  
  231. void
  232. dio_closegroup(chan)
  233. register CHAN *chan;
  234. {
  235.     register CHAN *nextc;
  236.  
  237.     for (chan = chan->base->list; chan; chan = nextc) {
  238.     chan = (CHAN *)((char *)chan - ((char *)&chan->link - (char *)chan));
  239.     nextc = (CHAN *)chan->link.next;
  240.     dio_close(chan);
  241.     }
  242. }
  243.  
  244.  
  245. CHAN *
  246. dio_dup(chan)
  247. register CHAN *chan;
  248. {
  249.     register CHAN *nc;
  250.  
  251.     if (chan) {
  252.     nc = (CHAN *)AllocMem(sizeof(CHAN), MPC);   if (!nc) goto fail2;
  253.     nc->ior = chan->ior;
  254.     nc->base = chan->base;
  255.     nc->CPORT = CreatePort(NULL,0);    if (!nc->CPORT) goto fail1;
  256.     nc->ior.ior.io_Flags = NULL;
  257.     nc->cact = chan->cact;
  258.     ++nc->base->refs;
  259.     llink(&nc->base->list, &nc->link);
  260.     return(nc);
  261. fail1:    FreeMem(nc, sizeof(CHAN));
  262.     }
  263. fail2:
  264.     return(NULL);
  265. }
  266.  
  267.  
  268. dio_signal(chan)
  269. CHAN *chan;
  270. {
  271.     if (chan)
  272.     return(chan->CPORT->mp_SigBit);
  273.     return(-1);
  274. }
  275.  
  276.  
  277. CHAN *
  278. dio_ctl_to(chan, com, buf, len, to)
  279. register CHAN *chan;
  280. char *buf;
  281. {
  282.     register long mask;
  283.  
  284.     if (!chan)
  285.     return(NULL);
  286.     if (chan->timer.io_Message.mn_ReplyPort == NULL) {
  287.     chan->timer.io_Message.mn_ReplyPort = chan->CPORT;
  288.     chan->timer.io_Command = TR_ADDREQUEST;
  289.     chan->timer.io_Actual = 0;
  290.     OpenDevice("timer.device", UNIT_VBLANK, &chan->timer);
  291.     }
  292.     mask = 1 << chan->CPORT->mp_SigBit;
  293.     dio_ctl(chan, (com>0)?-com:com, buf, len);    /* SendIO the request */
  294.     chan->timer.io_Length = to;     /* setup timer  */
  295.     SendIO(&chan->timer);        /* start timer  */
  296.     while (Wait(mask)) {        /* Wait for something */
  297.     if (CheckIO(chan))        /* request done  */
  298.         break;
  299.     if (CheckIO(&chan->timer)) {  /* timeout?  */
  300.         dio_abort(chan);
  301.         break;
  302.     }
  303.     }
  304.     AbortIO(&chan->timer);    /*  kill the timer  */
  305.     WaitIO(&chan->timer);    /*  remove from rp  */
  306.     return(chan);        /*  return ior    */
  307. }
  308.  
  309.  
  310. CHAN *
  311. dio_ctl(chan, com, buf, len)
  312. register CHAN *chan;
  313. char *buf;
  314. {
  315.     if (!chan)
  316.     return(NULL);
  317.     if (chan->notclear) {  /* wait previous req to finish */
  318.     WaitIO(chan);
  319.     chan->notclear = 0;
  320.     }
  321.     if (com) {
  322.     if (chan->cact)
  323.     chan->ior.ior.io_Actual = 0;        /* initialize io_Actual to 0*/
  324.     chan->ior.ior.io_Error = 0;        /* initialize error to 0 */
  325.     chan->ior.ior.io_Data = (APTR)buf;  /* buffer    */
  326.     chan->ior.ior.io_Length = len;        /* length    */
  327.     if (com < 0) {                /* asyncronous IO  */
  328.         chan->ior.ior.io_Command = -com;
  329.         chan->notclear = 1;
  330.         SendIO(chan);
  331.     } else {                /* syncronous IO  */
  332.         chan->ior.ior.io_Command = com;
  333.         DoIO(chan);
  334.     }
  335.     }
  336.     return(chan);
  337. }
  338.  
  339.  
  340. CHAN *
  341. dio_isdone(chan)
  342. register CHAN *chan;
  343. {
  344.     if (!chan)
  345.     return(NULL);
  346.     if (chan->notclear) {    /* if not clear */
  347.     if (CheckIO(chan)) {    /* if done    */
  348.         WaitIO(chan);    /* clear    */
  349.         chan->notclear = 0;
  350.         return(chan);    /* done    */
  351.     }
  352.      return(NULL);        /* notdone    */
  353.     }
  354.     return(chan);        /* done    */
  355. }
  356.  
  357.  
  358. CHAN *
  359. dio_wait(chan)
  360. register CHAN *chan;
  361. {
  362.     if (!chan)
  363.     return(NULL);
  364.     if (chan->notclear) {
  365.     WaitIO(chan);        /* wait and remove from rp */
  366.     chan->notclear = 0;
  367.     }
  368.     return(chan);
  369. }
  370.  
  371.  
  372. CHAN *
  373. dio_abort(chan)
  374. register CHAN *chan;
  375. {
  376.     if (!chan)
  377.     return(NULL);
  378.     if (chan->notclear) {
  379.     AbortIO(chan);        /* Abort it   */
  380.     WaitIO(chan);        /* wait and remove from rp */
  381.     chan->notclear = 0;
  382.     }
  383.     return(chan);
  384. }
  385.  
  386.  
  387.  
  388.